package com.horizon.common.repository;

import com.horizon.common.entity.IBaseEntity;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;

/**
 * 基本数据化操作基类
 *
 * @author wangfuwei
 * @version 2018-08-07
 */
@Repository
public class BaseRepository implements IBaseRepository {

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 持久化实体类
     *
     * @param entity 实体类
     */
    @Override
    public <T extends IBaseEntity> void persist(T entity) {
        entityManager.persist(entity);
    }

    /**
     * 删除实体类
     *
     * @param entity 实体类
     */
    @Override
    public <T extends IBaseEntity> void remove(T entity) {
        entityManager.remove(entity);
    }

    /**
     * 保存或更新实体类
     *
     * @param entity 实体类
     */
    @Override
    public <T extends IBaseEntity> T merge(T entity) {
        return entityManager.merge(entity);
    }

    /**
     * 根据主键查询实体类
     *
     * @param entityClass 实体类 Class
     * @param fdId        主键
     */
    @Override
    public <T extends IBaseEntity> T find(Class<T> entityClass, String fdId) {
        if (entityClass == null || fdId == null || fdId.isEmpty()) return null;
        T object = entityManager.find(entityClass, fdId);
        if (object == null) return null;
        return object;
    }

    /**
     * 根据主键查询实体类(懒加载)
     *
     * @param entityClass 实体类 Class
     * @param fdId        主键
     */
    @Override
    public <T extends IBaseEntity> T getReference(Class<T> entityClass, String fdId) {
        if (entityClass == null || fdId == null || fdId.isEmpty()) return null;
        T object = entityManager.getReference(entityClass, fdId);
        if (object == null) return null;
        return object;
    }

    /**
     * 根据主键判断存在持久化实体类
     *
     * @param entityClass 实体类 Class
     * @param fdId        主键
     */
    @Override
    public <T extends IBaseEntity> Boolean isExist(Class<T> entityClass, String fdId) {
        return this.find(entityClass, fdId) != null;
    }

    /**
     * 根据HQL语句查询列表数据
     *
     * @param hqlInfo HQL语句
     */
    @Override
    public <T> List<T> findList(HQLInfo hqlInfo) {
        return createHbmQuery(hqlInfo, false).getResultList();
    }

    /**
     * 根据HQL语句查询分页数据
     *
     * @param hqlInfo HQL语句
     */
    @Override
    public Page findPage(HQLInfo hqlInfo) {
        Page page = new Page();
        Integer total = ((Long) createHbmQuery(hqlInfo, true).getSingleResult()).intValue();
        if (total > 0) {
            page.setRowsize(hqlInfo.getRowSize());
            page.setPageno(hqlInfo.getPageNo());
            page.setTotalrows(total);
            page.excecute();
            Query query = createHbmQuery(hqlInfo, false);
            query.setFirstResult(page.getStart());
            query.setMaxResults(page.getRowsize());
            page.setList(query.getResultList());
        } else {
            page.getEmptyPage();
        }
        return page;
    }

    /**
     * 获取HQL Query对象
     *
     * @param hql HQL语句
     */
    @Override
    public Query HQLQuery(String hql) {
        return entityManager.createQuery(hql);
    }

    /**
     * 获取SQL Query对象
     *
     * @param sql SQL语句
     */
    @Override
    public Query SQLQuery(String sql) {
        return entityManager.createNativeQuery(sql);
    }

    /**
     * 刷新实体对象
     *
     * @param entity 实体对象
     */
    @Override
    public <T extends IBaseEntity> void refresh(T entity) {
        entityManager.refresh(entity);
    }

    /**
     * 刷新缓存
     */
    @Override
    public void flush() {
        entityManager.flush();
    }

    /**
     * 封装为Query查询对象
     *
     * @param hqlInfo HQL语句
     */
    private Query createHbmQuery(HQLInfo hqlInfo, Boolean isCount) {
        Query query = entityManager.createQuery(hqlInfo.buildHQL(isCount));

        Map<String, Object> parameterMap = hqlInfo.getParameterMap();
        for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        return query;
    }
}
